package reflect0

import (
	"fmt"
	"reflect"
)

type Company struct {
	Name    string
	Address string
}
type User struct {
	Id   int64  `column:id`
	Name string `column:name`
	Age  int8   `column:age`
}

func (u User) Hello() {
	fmt.Println("Hello")
}

type Merchant struct {
	User
	Money int64
	C     *Company
}

func (Merchant) Show(m int64) {
	fmt.Println("----func (Merchant) Show(m int64) ----------------", m)
}

func (*Merchant) Pay(m int64) {
	fmt.Println("----func (*Merchant) Pay(m int64)  ----------------", m)

}

func RefelctStructType() {
	m := Merchant{}
	m.Id = 1232
	m.Name = "Mike"
	m.Age = 54
	m.Money = 2000000000
	m.C = &Company{Name: "永兴", Address: "上海市南京路1号"}

	t := reflect.TypeOf(m)
	fmt.Println("t类型：", t, ",是否指针：", t.Kind() == reflect.Ptr)
	fmt.Println("t类型名称：", t.Name())
	tk := t.Kind()
	fmt.Println("t类型分类：", tk.String())

	pt := reflect.TypeOf(&m)
	fmt.Println("pt类型：", pt, ",是否指针：", pt.Kind() == reflect.Ptr)
	fmt.Println("pt类型名称：", pt.Name())
	ptk := pt.Kind()
	fmt.Println("pt类型分类：", ptk.String())

}
func RefelctStructField() {
	m := Merchant{}
	m.Id = 1232
	m.Name = "Mike"
	m.Age = 54
	m.Money = 2000000000
	m.C = &Company{Name: "永兴", Address: "上海市南京路1号"}

	t := reflect.TypeOf(m)
	// 因为要改变m的属性值所以reflect.ValueOf要用指针否者是m的拷贝，指针还要用Elem()获取指向的真实对象
	v := reflect.ValueOf(&m).Elem()
	fmt.Println("值：", v, v.CanSet())

	for i, n := 0, t.NumField(); i < n; i++ {
		// 取每个字段
		ft := t.Field(i)
		fv := v.Field(i)
		fmt.Printf("第 %d 个属性名：%s ,属性类型： %v ,是否私有：%t,是否指针：%t,是否结构体：%t,是否嵌入属性：%t,属性值：%+v ,是否可以改变值：%t \n",
			i, ft.Name, ft.Type, IsLowerAlphabetic(([]rune(ft.Name))[0]), ft.Type.Kind() == reflect.Ptr, ft.Type.Kind() == reflect.Struct, ft.Anonymous, fv.Interface(), fv.CanSet())

		if 1 == i {
			fv.SetInt(666666)
		}

	}
	fmt.Printf("################## %+v", m)

}

func RefelctStructField2() {
	m := Merchant{}
	m.Id = 1232
	m.Name = "Mike"
	m.Age = 54
	m.Money = 2000000000
	m.C = &Company{Name: "永兴", Address: "上海市南京路1号"}

	refelctStructField0(&m)

	fmt.Printf("################## %+v", m)

}
func refelctStructField0(m *Merchant) {

	t := reflect.TypeOf(*m)
	// 因为要改变m的属性值所以reflect.ValueOf要用指针否者是m的拷贝，指针还要用Elem()获取指向的真实对象
	v := reflect.ValueOf(m).Elem()
	fmt.Println("值：", v, v.CanSet())

	for i, n := 0, t.NumField(); i < n; i++ {
		// 取每个字段
		ft := t.Field(i)
		fv := v.Field(i)
		fmt.Printf("第 %d 个属性名：%s ,属性类型： %v ,是否私有：%t,是否指针：%t,是否结构体：%t,是否嵌入属性：%t,属性值：%+v ,是否可以改变值：%t \n",
			i, ft.Name, ft.Type, IsLowerAlphabetic(([]rune(ft.Name))[0]), ft.Type.Kind() == reflect.Ptr, ft.Type.Kind() == reflect.Struct, ft.Anonymous, fv.Interface(), fv.CanSet())

		if 1 == i {
			fv.SetInt(666666)
		}

	}
	fmt.Printf("################## %+v", m)

}

func RefelctStructMethod() {
	m := Merchant{}
	m.Id = 1232
	m.Name = "Mike"
	m.Age = 54
	m.Money = 2000000000
	m.C = &Company{Name: "永兴", Address: "上海市南京路1号"}

	t := reflect.TypeOf(m)
	v := reflect.ValueOf(&m).Elem()
	fmt.Println("值：", v)

	(&m).Pay(int64(57788))
	//TODO 可以调用打但反射不到指针接收者方法?
	mnv := v.MethodByName("Pay")
	fmt.Println(mnv)
	if (mnv != reflect.Value{}) {
		mnv.Call([]reflect.Value{reflect.ValueOf(int64(2362324))})
	} else {
		fmt.Println("no method Pay")
	}

	for i, n := 0, v.NumMethod(); i < n; i++ {
		mt := t.Method(i)
		mv := v.Method(i)
		fmt.Printf("第 %d 个方法名：%s ,属性类型： %v ,是否私有：%t,入参数量：%d,出参数量:  %d,接收者类型: %+v,是否指针:%t \n",
			i, mt.Name, mt.Type, IsLowerAlphabetic(([]rune(mt.Name))[0]), mt.Type.NumIn(), mt.Type.NumOut(), mt.Type.In(0), mt.Type.In(0).Kind() == reflect.Ptr)
		if 1 == mt.Type.NumIn() {
			mv.Call([]reflect.Value{})
		} else {
			i0 := int64(i)
			mv.Call([]reflect.Value{reflect.ValueOf(i0)})
		}

	}

}

/*
*
是否小写字母
*/
func IsLowerAlphabetic(c rune) bool {
	return 'a' <= c && c <= 'z'
}

func ReflectFunction() {
	funcType := reflect.TypeOf(IsLowerAlphabetic)
	fmt.Println("funcType类型：", funcType, ",是否指针：", funcType.Kind() == reflect.Ptr, ",是否函数：", funcType.Kind() == reflect.Func)
	fmt.Println("funcTypet类型名称：", funcType.Name())
	fmt.Printf("方法名：%s ,属性类型： %v ,入参数量：%d,出参数量:  %d,接收者类型: %+v,是否指针:%t \n",
		funcType.Name(), funcType, funcType.NumIn(), funcType.NumOut(), funcType.In(0), funcType.In(0).Kind() == reflect.Ptr)

}
